package com.example.bluetooth;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
public class ChatService {

    private final BluetoothAdapter mAdapter;
    private final Handler mHandler ;
    private AcceptThread mAcceptThread;
    private ConnectThread mConnectThread;
    private ConnectedThread mConnectedThread;
    private int mState;
    private final String NAME="MainActivity";
    // UUID-->通用唯一识别码，能唯一地辨识咨询
    private static final UUID MY_UUID=UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");//串口

    public static final int STATE_NONE = 0;     // 空闲
    public static final int STATE_LISTEN = 1;   // 监听连接
    public static final int STATE_CONNECTING = 2;   // 连接中
    public static final int STATE_CONNECTED = 3;    // 已连接

    public ChatService(Context context, Handler handler){
        mAdapter=BluetoothAdapter.getDefaultAdapter();
        mState = STATE_NONE;
        mHandler = handler;
    }

    private synchronized void setState(int state){
        mState = state;
        mHandler.obtainMessage(MainActivity.MESSAGE_STATE_CHANGE,state,-1).sendToTarget();
    }

    public synchronized int getState(){
        return mState;
    }

    public synchronized void start(){
        if(mConnectThread !=null){
            mConnectThread.cancel();
            mConnectThread=null;
        }

        if(mConnectedThread !=null){
            mConnectedThread.cancel();
            mConnectedThread=null;
        }

        if (mAcceptThread == null){
            mAcceptThread = new AcceptThread();
            mAcceptThread.start();
        }
        setState(STATE_LISTEN);
    }

    // 取消 Connecting Connected状态下的相关线程，然后运行新的mConnectThread线程
    public synchronized void connect(BluetoothDevice device){
        Log.e("ChatTag", " 设备名字：" +device.getName());
        if(mState == STATE_CONNECTED){
            if(mConnectThread !=null){
                mConnectThread.cancel();
                mConnectThread=null;
            }
        }
        if(mConnectedThread !=null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }
        if(mAcceptThread != null){
            mAcceptThread.cancel();
            mAcceptThread =null;
        }
        mConnectThread = new ConnectThread(device);
        mConnectThread.start();
        setState(STATE_CONNECTING);
    }

    // 开启一个ConnectThread来管理对应的当前连接。之前取消任意现存的mConnectThread
    // mConnectThread，mAcceptThread线程，然后开启新的mConnectThread，传入当前
    // 刚刚接受的socket连接，最后通过Handler来通知UI连接
    public synchronized void connected(BluetoothSocket socket, BluetoothDevice device){
        Log.e("ChatTag", " -- connected(BluetoothSocket socket, BluetoothDevice device) - ");
        if(mConnectThread !=null){
            mConnectThread.cancel();
            mConnectThread=null;
        }
        if(mConnectedThread !=null){
            mConnectedThread.cancel();
            mConnectedThread=null;
        }
        if(mAcceptThread !=null){
            mAcceptThread.cancel();
            mAcceptThread=null;
        }
        mConnectedThread=new ConnectedThread(socket);
        mConnectedThread.start();


        Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_DEVICE_NAME);
        Bundle bundle = new Bundle();
        bundle.putString(MainActivity.DEVICE_NAME,device.getName());
        msg.setData(bundle);
        mHandler.sendMessage(msg);
        setState(STATE_CONNECTED);
        Log.e("ChatTag", " -- MESSAGE_DEVICE_NAME -- ");
    }

    // 停止所有相关线程，设当前状态为none
    public synchronized void stop(){
        if(mConnectThread !=null){
            mConnectThread.cancel();
            mConnectThread=null;
        }
        if(mConnectedThread !=null){
            mConnectedThread.cancel();
            mConnectedThread=null;
        }
        if(mAcceptThread !=null){
            mAcceptThread.cancel();
            mAcceptThread=null;
        }
        setState(STATE_NONE);
    }

    // 在STATE_CONNECTED状态下，调用mConnectedThread里的write方法，写入byte
    public void write(byte[]out){
        ConnectedThread r;
        synchronized (this){
            if(mState != STATE_CONNECTED)
                return;
            r = mConnectedThread;
        }
        r.write(out);
    }

    // 连接失败的时候处理，通知UI，并设为STATE_LISTEN状态
    private void connectionFailed(){
        setState(STATE_LISTEN);
        Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);
        Bundle bundle=new Bundle();
        bundle.putString(MainActivity.TOAST,"连接不到设备");
        msg.setData(bundle);
        mHandler.sendMessage(msg);

        ChatService.this.start();
    }

    // 当连接失去的时候，设为STATE_LISTEN
    private void connectionLost(){
        setState(STATE_LISTEN);
        Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);
        Bundle bundle=new Bundle();
        bundle.putString(MainActivity.TOAST,"设备连接中断");
        msg.setData(bundle);
        mHandler.sendMessage(msg);
        ChatService.this.start();
    }


    // 创建监听线程，准备接受新连接。使用阻塞方式，调用BluetoothServerSocket.accept()
    private class AcceptThread extends Thread {
        private final BluetoothServerSocket mmServerSocket;
        public AcceptThread(){
            BluetoothServerSocket tmp = null;
            try{
                //MY_UUID用于唯一标识当前的蓝牙服务，在建立连接时会被客户端使用
                tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME,MY_UUID);
            }catch (IOException e){}
            mmServerSocket = tmp;
        }
        public void run(){
            BluetoothSocket socket= null;
            while(mState != STATE_CONNECTED){
                try{
                    // 保持监听状态，并阻塞线程，当连接建立时返回。
                    socket = mmServerSocket.accept();
                }catch (IOException e) {
                    break;
                }
                if(socket != null){
                    //在单独的线程中对连接进行管理，本线程结束
                    connected(socket,socket.getRemoteDevice());
                    try{
                        mmServerSocket.close();
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }
            }
        }
        public void cancel(){
            try{
                mmServerSocket.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }


    private class ConnectThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;
        public ConnectThread(BluetoothDevice device){
            Log.e("ChatTag", " -- ConnectThread -- ");
            mmDevice=device;
            BluetoothSocket tmp = null;
            //获取一个 BluetoothSocket 以连接给定的 BluetoothDevice
            try{
                // MY_UUID 是应用程序的 UUID 字符串，也由服务器代码使用
                tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
            }catch (IOException e){
                e.printStackTrace();
            }
            mmSocket = tmp;
        }

        public void run(){
            // 取消发现，因为它会减慢连接速度
            mAdapter.cancelDiscovery();
            try{
                // 请求连接，该操作会阻塞线程
                // 直到成功或抛出异常
                mmSocket.connect();
                Log.e("ChatTag", " -- ConnectThread - connect() - ");
            }catch (IOException e){
                e.printStackTrace();

                Log.e("ChatTag", " -- ConnectThread - connect() - IOException - ");
                connectionFailed();
                // Unable to connect; close the socket and get out
                try{
                    mmSocket.close();
                }catch (IOException e2){}
                //ChatService.this.start();
                return;
            }
            synchronized(ChatService.this){
                mConnectedThread = null;
            }
            // 连接已建立，在单独的线程中对连接进行管理
            connected(mmSocket,mmDevice);
        }

        public void cancel(){
            /* try{
                mmSocket.close();
            }catch (IOException e){}*/
        }
    }

    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private  InputStream mmInStream;
        private  OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket){
            Log.e("ChatTag", " -- ConnectedThread -- ");
            mmSocket = socket;
            // 使用临时对象获取输入和输出流
            try{
                mmInStream = mmSocket.getInputStream();
                mmOutStream = mmSocket.getOutputStream();
                Log.e("ChatTag", " -- ConnectedThread -- ");
            }catch (IOException e){}
        }

        public void run(){
            byte[]buffer=new byte[1024];
            int bytes;
            //读数据需要不断监听 ，写 不需要
            while (true) {
                try {
                    Log.e("ChatTag", " -- ConnectedThread - run() - 1 - ");
                    //读取 InputStream 的数据
                    bytes = mmInStream.read(buffer);
                    Log.e("ChatTag", " -- ConnectedThread - run()  - 2 - ");
                    // 更新 UI
                    mHandler.obtainMessage(MainActivity.MESSAGE_READ,bytes,-1,buffer).sendToTarget();
                    Log.e("ChatTag", " -- ConnectedThread - run()  - 3 - ");
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.e("ChatTag", " -- ConnectedThread - run()- IOException- ");
                    connectionLost();
                    break;
                }
            }
        }

        public void write(byte[]buffer){
            try{
                mmOutStream.write(buffer);
            }catch (IOException e){
                Log.d("MainActivity","Send Fail");
            }
            mHandler.obtainMessage(MainActivity.MESSAGE_WRITE,buffer).sendToTarget();
        }

        public void cancel(){
            try{
                mmSocket.close();
            }catch (IOException e){}
        }
    }


}
